/*!
 * 简化的Rust项目构建器
 * 
 * 将LLM转换的结果构建成完整的Cargo项目
 */

use anyhow::{Result, Context};

/// 编译结果
#[derive(Debug)]
pub struct CompileResult {
    pub success: bool,
    pub errors: Vec<CompileError>,
    pub warnings: Vec<String>,
    pub full_output: String,
}

/// 编译错误详情
#[derive(Debug, Clone)]
pub struct CompileError {
    pub message: String,
    pub file: String,
    pub line_number: Option<u32>,
    pub details: Vec<String>,
}
use std::fs;
use std::path::Path;

use crate::llm_converter::RustProject;

/// 项目构建器
pub struct ProjectBuilder;

impl ProjectBuilder {
    pub fn new() -> Self {
        Self
    }
    
    /// 构建Cargo项目
    pub fn build_project(&self, rust_project: &RustProject, output_path: &Path) -> Result<()> {
        log::info!("构建Cargo项目到: {:?}", output_path);
        
        // 创建项目目录
        fs::create_dir_all(output_path)
            .with_context(|| format!("创建项目目录失败: {:?}", output_path))?;
        
        let src_dir = output_path.join("src");
        fs::create_dir_all(&src_dir)
            .with_context(|| "创建src目录失败")?;
        
        // 生成Cargo.toml
        self.generate_cargo_toml(rust_project, output_path)?;
        
        // 生成源文件
        if rust_project.is_binary {
            self.generate_binary_project(rust_project, &src_dir)?;
        } else {
            self.generate_library_project(rust_project, &src_dir)?;
        }
        
        log::info!("Cargo项目构建完成");
        Ok(())
    }
    
    /// 生成Cargo.toml
    fn generate_cargo_toml(&self, project: &RustProject, project_path: &Path) -> Result<()> {
        let cargo_content = format!(
r#"[package]
name = "{}"
version = "0.1.0"
edition = "2021"

[dependencies]
{}

[lib]
name = "{}"
{}
"#,
            project.name,
            self.format_dependencies(&project.dependencies),
            project.name.replace("-", "_"),
            if project.is_binary {
                format!("\n[[bin]]\nname = \"{}\"\npath = \"src/main.rs\"", project.name)
            } else {
                String::new()
            }
        );
        
        let cargo_path = project_path.join("Cargo.toml");
        fs::write(cargo_path, cargo_content)
            .with_context(|| "写入Cargo.toml失败")?;
        
        Ok(())
    }
    
    /// 生成二进制项目结构
    fn generate_binary_project(&self, project: &RustProject, src_dir: &Path) -> Result<()> {
        // 查找main模块
        let main_module = project.modules.iter()
            .find(|m| m.name == "main" || m.content.contains("fn main("));
        
        let main_module_name = main_module.map(|m| m.name.as_str());
        
        if let Some(main_mod) = main_module {
            // 生成main.rs
            fs::write(src_dir.join("main.rs"), &main_mod.content)
                .with_context(|| "写入main.rs失败")?;
            log::info!("将模块 '{}' 作为 main.rs", main_mod.name);
        } else {
            // 生成基本的main.rs
            let main_content = format!(
r#"//! {} - 主程序入口

fn main() {{
    println!("Hello from {}!");
    // TODO: 调用转换后的C函数
}}
"#,
                project.name, project.name
            );
            fs::write(src_dir.join("main.rs"), main_content)
                .with_context(|| "写入main.rs失败")?;
            log::info!("生成默认 main.rs");
        }
        
        // 生成其他模块文件（排除已经作为 main.rs 的模块）
        for module in &project.modules {
            if Some(module.name.as_str()) != main_module_name {
                let module_file = src_dir.join(format!("{}.rs", module.name));
                fs::write(&module_file, &module.content)
                    .with_context(|| format!("写入模块文件失败: {}", module.name))?;
                log::debug!("生成模块文件: {}.rs", module.name);
            }
        }
        
        // 生成lib.rs以便其他模块可以被引用
        self.generate_lib_rs(project, src_dir)?;
        
        Ok(())
    }
    
    /// 生成库项目结构
    fn generate_library_project(&self, project: &RustProject, src_dir: &Path) -> Result<()> {
        // 生成lib.rs
        self.generate_lib_rs(project, src_dir)?;
        
        // 生成各个模块文件
        for module in &project.modules {
            let module_file = src_dir.join(format!("{}.rs", module.name));
            fs::write(module_file, &module.content)
                .with_context(|| format!("写入模块文件失败: {}", module.name))?;
        }
        
        Ok(())
    }
    
    /// 生成lib.rs
    fn generate_lib_rs(&self, project: &RustProject, src_dir: &Path) -> Result<()> {
        let mut lib_content = String::new();
        
        // 文档注释
        lib_content.push_str(&format!(
r#"//! {} - 从C代码自动转换而来的Rust库
//!
//! 这个库是通过LLM智能转换系统从C代码自动生成的。
//! 
//! # 安全性说明
//! 
//! 本库可能包含unsafe代码块，使用时请注意内存安全。

"#,
            project.name
        ));
        
        // 导出所有模块
        for module in &project.modules {
            if module.name != "main" {
                lib_content.push_str(&format!("pub mod {};\n", module.name));
            }
        }
        
        // 重新导出主要内容
        lib_content.push_str("\n// 重新导出主要内容\n");
        for module in &project.modules {
            if module.name != "main" {
                lib_content.push_str(&format!("pub use {}::*;\n", module.name));
            }
        }
        
        fs::write(src_dir.join("lib.rs"), lib_content)
            .with_context(|| "写入lib.rs失败")?;
        
        Ok(())
    }
    
    /// 格式化依赖声明
    fn format_dependencies(&self, dependencies: &[String]) -> String {
        if dependencies.is_empty() {
            return String::new();
        }
        
        let mut deps = Vec::new();
        for dep in dependencies {
            match dep.as_str() {
                "libc" => deps.push("libc = \"0.2\"".to_string()),
                "regex" => deps.push("regex = \"1.0\"".to_string()),
                "serde" => deps.push("serde = { version = \"1.0\", features = [\"derive\"] }".to_string()),
                _ => deps.push(format!("{} = \"1.0\"", dep)),
            }
        }
        deps.join("\n")
    }
    
    /// 验证生成的项目
    pub fn validate_project(&self, project_path: &Path) -> Result<()> {
        log::info!("验证生成的Cargo项目...");
        
        // 检查基本文件
        let cargo_toml = project_path.join("Cargo.toml");
        if !cargo_toml.exists() {
            return Err(anyhow::anyhow!("Cargo.toml不存在"));
        }
        
        let src_dir = project_path.join("src");
        if !src_dir.exists() {
            return Err(anyhow::anyhow!("src目录不存在"));
        }
        
        let lib_rs = src_dir.join("lib.rs");
        if !lib_rs.exists() {
            return Err(anyhow::anyhow!("lib.rs不存在"));
        }
        
        log::info!("项目结构验证通过");
        Ok(())
    }
    
    /// 编译检查项目并提取错误信息
    pub fn compile_check(&self, project_path: &Path) -> Result<CompileResult> {
        log::info!("执行编译检查...");
        
        let output = std::process::Command::new("cargo")
            .arg("check")
            .arg("--color=never") // 避免颜色代码干扰
            .current_dir(project_path)
            .output()
            .with_context(|| "执行cargo check失败")?;
        
        let stderr = String::from_utf8_lossy(&output.stderr);
        let stdout = String::from_utf8_lossy(&output.stdout);
        
        let compile_output = format!("{}\n{}", stdout, stderr);
        
        if output.status.success() {
            log::info!("编译检查通过！");
            Ok(CompileResult {
                success: true,
                errors: Vec::new(),
                warnings: self.extract_warnings(&compile_output),
                full_output: compile_output,
            })
        } else {
            log::warn!("编译检查发现错误");
            let errors = self.extract_errors(&compile_output);
            let warnings = self.extract_warnings(&compile_output);
            
            Ok(CompileResult {
                success: false,
                errors,
                warnings,
                full_output: compile_output,
            })
        }
    }
    
    /// 提取编译错误
    fn extract_errors(&self, output: &str) -> Vec<CompileError> {
        let mut errors = Vec::new();
        let lines: Vec<&str> = output.lines().collect();
        
        log::debug!("===== 错误解析调试信息 =====");
        log::debug!("编译输出行数: {}", lines.len());
        
        for (i, line) in lines.iter().enumerate() {
            if line.starts_with("error") {
                let mut error = CompileError {
                    message: line.to_string(),
                    file: String::new(),
                    line_number: None,
                    details: Vec::new(),
                };
                
                log::debug!("找到错误行 {}: {}", i, line);
                
                // 查找文件位置信息和收集详细错误信息 (格式: --> src/file.rs:line:col)
                let mut found_location = false;
                for j in (i+1).min(lines.len())..lines.len().min(i + 15) {  // 扩大搜索范围
                    if let Some(location_line) = lines.get(j) {
                        log::debug!("检查位置行 {}: {}", j, location_line);
                        
                        // 首先尝试提取文件位置信息
                        if !found_location && location_line.contains("-->") {
                            log::debug!("找到位置指示符: {}", location_line);
                            if let Some(path_part) = location_line.split("-->").nth(1) {
                                let path_part = path_part.trim();
                                log::debug!("提取路径部分: '{}'", path_part);
                                
                                if let Some(colon_pos) = path_part.find(':') {
                                    error.file = path_part[..colon_pos].to_string();
                                    log::debug!("提取文件名: '{}'", error.file);
                                    
                                    if let Some(line_part) = path_part[(colon_pos+1)..].split(':').next() {
                                        error.line_number = line_part.parse().ok();
                                        log::debug!("提取行号: {:?}", error.line_number);
                                    }
                                } else {
                                    // 没有冒号，整个就是文件名
                                    error.file = path_part.to_string();
                                    log::debug!("文件名（无行号）: '{}'", error.file);
                                }
                            }
                            found_location = true;
                        }
                        
                        // 收集相关的详细信息（不管是否找到位置，都要继续收集）
                        if !location_line.trim().is_empty() {
                            let trimmed = location_line.trim();
                            // 收集所有可能有用的行：代码行、错误说明、提示等
                            if trimmed.contains("|") 
                                || trimmed.starts_with("=") 
                                || trimmed.contains("expected") 
                                || trimmed.contains("found")
                                || trimmed.contains("help:")
                                || trimmed.contains("note:")
                                || trimmed.contains("-->")
                                || trimmed.starts_with("For more information") {
                                log::debug!("收集详细信息: {}", location_line);
                                error.details.push(location_line.to_string());
                            }
                        }
                        
                        // 如果遇到新的错误或警告开始，停止收集
                        if location_line.trim().starts_with("error") && j > i + 3 {
                            log::debug!("遇到新错误，停止收集详情");
                            break;
                        }
                        if location_line.trim().starts_with("warning") && j > i + 3 {
                            log::debug!("遇到新警告，停止收集详情");
                            break;
                        }
                    }
                }
                
                log::debug!("完成错误解析: 文件='{}', 消息='{}'", error.file, error.message);
                errors.push(error);
            }
        }
        
        log::debug!("总共解析到 {} 个错误", errors.len());
        log::debug!("===========================");
        
        errors
    }
    
    /// 提取编译警告
    fn extract_warnings(&self, output: &str) -> Vec<String> {
        output.lines()
            .filter(|line| line.starts_with("warning"))
            .map(|line| line.to_string())
            .collect()
    }
}